MOOC Utils

Utils like auto assignment solver extension and course notice announcment notification for MOOC courses

Subscriptions management API

Introduction#

CRUD for course subscriptions in notice-reminders. Create, update, and delete subscriptions, with duplicate checks and ownership enforced in the service layer. Preference and notification settings that exist in code are documented; anything not implemented yet is marked as such.

Project structure#

The subscription management feature is implemented in the notice-reminders backend (FastAPI application). Key components include:

  • API router exposing subscription endpoints
  • Service layer implementing subscription logic
  • Pydantic schemas for request/response validation
  • Tortoise ORM models for persistence
  • Dependencies for service injection
  • Related notification channel models and services

Core components#

  • Subscription API Router: Exposes endpoints for creating, listing, and deleting subscriptions under /subscriptions.
  • Subscription Service: Implements subscription logic including duplicate prevention and retrieval.
  • Subscription Model: Defines the subscription entity with foreign keys to User and Course, timestamps, and activation flag.
  • Course Model: Provides course metadata and uniqueness constraints.
  • User Model: Identifies users and supports authentication-dependent operations.
  • Notification Channel Models and Services: Manage user notification preferences and channels.

Key capabilities:

  • Create subscription via course code with duplicate prevention
  • List subscriptions per user
  • Delete subscription with ownership verification
  • Manage notification channels and preferences
  • Announcements caching and retrieval for course subscriptions

Architecture overview#

The subscription management architecture follows a layered pattern:

  • API Router handles HTTP requests and injects services via FastAPI Depends
  • Service layer encapsulates business logic and interacts with models
  • Persistence layer uses Tortoise ORM with unique constraints to prevent duplicates
  • Authentication middleware so only authenticated users can access subscription endpoints

Detailed component analysis#

Subscription endpoints#

  • Base path: /subscriptions
  • Authentication: All endpoints require authentication via require_auth decorator

Endpoints:

  • POST /subscriptions

  • Purpose: Create a subscription for a course by code

  • Request body: SubscriptionCreate (course_code)

  • Response: SubscriptionResponse (id, user_id, course_id, is_active, created_at)

  • Status codes: 201 Created, 404 Not Found (course missing)

  • Validation: Course existence checked before subscription creation

  • GET /subscriptions

  • Purpose: List all subscriptions for the authenticated user

  • Response: Array of SubscriptionResponse

  • Status codes: 200 OK

  • DELETE /subscriptions/{subscription_id}

  • Purpose: Cancel a subscription

  • Path parameter: subscription_id (int)

  • Response: No content (204)

  • Status codes: 404 Not Found (subscription missing), 403 Forbidden (access denied)

Authorization and ownership checks:

  • DELETE endpoint verifies that the subscription belongs to the current user before deletion

Subscription service#

Responsibilities:

  • subscribe(user, course): Creates a subscription; if a duplicate exists (unique constraint), returns the existing subscription
  • list_for_user(user): Retrieves all subscriptions for a user ordered by creation time
  • list_all(): Retrieves all subscriptions ordered by creation time
  • delete(subscription): Removes a subscription

Duplicate prevention:

  • Uses database unique constraint on (user, course) enforced by Tortoise model definition
  • On IntegrityError during creation, retrieves the existing subscription

Status management:

  • Subscription records include is_active flag; service does not toggle it on create/delete

Data models and schemas#

Models:

  • Subscription: Links User and Course, tracks creation time, and activation status
  • Course: Course metadata with unique code
  • User: User identity with optional Telegram ID and activity flag
  • NotificationChannel: User notification preferences with channel/address and activation

Schemas:

  • SubscriptionCreate: course_code
  • SubscriptionResponse: id, user_id, course_id, is_active, created_at
  • NotificationChannelCreate: channel, address, is_active
  • NotificationChannelResponse: id, user_id, channel, address, is_active, created_at

Unique constraints:

  • Subscription: unique_together (user, course)
  • Course: unique code
  • NotificationChannel: unique_together (user, channel, address)

Notification preferences and channels#

Endpoints:

  • GET /notification-channels (conceptual, see service usage below)
  • POST /notification-channels (conceptual)
  • PATCH /notification-channels/{id}/disable (conceptual)

Services:

  • NotificationChannelService: list_for_user, create, disable
  • Behavior: Prevents duplicate channels per user-channel-address combination via unique constraint

Integration:

  • Notification preferences complement subscriptions by controlling how and where users receive updates

Announcements and subscription analytics#

Announcements:

  • AnnouncementService fetches and caches announcements per course
  • Deduplicates announcements by title and date; updates content if changed
  • Supports listing announcements for a course

Analytics and usage tracking:

  • Announcement caching provides historical context for subscription analytics
  • Subscription listing enables usage tracking per user and course

Dependency analysis#

Service injection and routing:

  • API router depends on CourseService and SubscriptionService via get_* dependency functions
  • Dependencies module provides cached instances of services
  • Application wiring includes subscription router in main app factory

Performance considerations#

  • Unique constraints on (user, course) and (user, channel, address) prevent redundant writes and improve lookup performance
  • Ordering by created_at in list queries so recent subscriptions appear first
  • Announcement caching reduces repeated external API calls and database writes
  • Consider adding pagination for listing endpoints if subscription volumes grow large

Troubleshooting guide#

Common errors and resolutions:

  • 404 Not Found when creating subscription:

  • Cause: Course code does not exist

  • Resolution: Verify course code or fetch course list first

  • 404 Not Found when deleting subscription:

  • Cause: Subscription ID does not exist

  • Resolution: Refresh subscription list and confirm ID

  • 403 Forbidden when deleting subscription:

  • Cause: Subscription does not belong to the current user

  • Resolution: Ensure user context matches subscription owner

  • Duplicate subscription creation:

  • Behavior: Service returns existing subscription instead of raising error

  • Resolution: No action needed; idempotent behavior prevents duplication

Conclusion#

Subscriptions are owned rows with duplicate prevention. Status toggles and renewals are not in the handlers yet, even if the models could grow into them.